package com.bytedance.news.common.service.manager;

import java.util.concurrent.ConcurrentHashMap;

/**
 * Service的管理类，用于服务的注册与获取
 * https://wiki.bytedance.net/pages/viewpage.action?pageId=323718762
 *
 * @author shiguangyin
 * @date 2019/1/31
 */
public class ServiceManager {

    private static final ConcurrentHashMap<Class, Object> SERVICES = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<Class, ServiceCreator<?>> SERVICE_CREATORS = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<Class, ServiceLoadListener> SERVICE_LOAD_LISTENERS = new ConcurrentHashMap<>();


    /***
     *  获取指定接口的实现类
     *
     * @param clazz 指定接口的class
     * @return 实现了该接口的一个实例，如果找不到会返回null
     */
    @SuppressWarnings("unchecked")
    public static <T> T getService(Class<T> clazz) {
        T impl = (T) SERVICES.get(clazz);
        if (impl == null) {
            synchronized (clazz) {
                // double check
                impl = (T) SERVICES.get(clazz);
                if (impl != null) {
                    return impl;
                }
                ServiceCreator<T> creator = (ServiceCreator<T>) SERVICE_CREATORS.get(clazz);
                if (creator != null) {
                    impl = creator.create();
                    SERVICE_CREATORS.remove(clazz);
                    if (impl != null) {
                        putService(clazz, impl);
                        return impl;
                    }
                }
                impl = ServiceFinder.findService(clazz);
                if (impl != null) {
                    putService(clazz, impl);
                    return impl;
                }
                impl = tryGetByReflect(clazz);
                if (impl != null) {
                    putService(clazz, impl);
                    return impl;
                }
            }
        }
        return impl;
    }


    /**
     * 手动为接口注册实现类
     * @param clazz 接口的class
     * @param obj 实现了该接口的实例
     */
    public static <T> void registerService(Class<T> clazz, T obj) {
        SERVICES.put(clazz, obj);
    }


    /**
     * 手动为接口注册ServiceCreator
     * @param clazz 接口的class
     * @param creator 根据指定的class创建实例
     * ServiceCreator可以负责创建多个Service的实例从而实现懒加载
     */
    public static <T> void registerService(Class<T> clazz, ServiceCreator<T> creator) {
        SERVICE_CREATORS.put(clazz, creator);
    }

    /**
     *  取消注册
     */
    public static <T> void unregisterService(Class<T> clazz, T obj) {
        SERVICES.remove(clazz, obj);
    }

    /**
     * 注册Service 加载成功的回调，只会回调一次，回调后自动remove
     * @param clazz Service 接口的class
     * @param listener 实现类首次获取成功的回调
     * @param <T> Service的接口类型
     */
    public static <T> void registerServiceLoadListener(Class<T> clazz, ServiceLoadListener<T> listener) {
        SERVICE_LOAD_LISTENERS.put(clazz, listener);
    }

    @SuppressWarnings("unchecked")
    private static <T> void putService(Class<T> clazz, T impl) {
        SERVICES.put(clazz, impl);
        ServiceLoadListener listener = SERVICE_LOAD_LISTENERS.get(clazz);
        if (listener != null) {
            listener.onServiceLoaded(impl);
            SERVICE_LOAD_LISTENERS.remove(clazz);
        }
    }

    @SuppressWarnings("unchecked")
    private static <T> T tryGetByReflect(Class<T> clazz) {
        String ifsName = clazz.getName();
        String proxyClassName = String.format("%s__ServiceProxy", ifsName);
        try {
            Class proxyClass = Class.forName(proxyClassName);
            Object proxyInstance = proxyClass.newInstance();
            if (proxyInstance instanceof IServiceProxy) {
                return (T) ((IServiceProxy) proxyInstance).newInstance();
            }
        } catch (Exception ignore) {
            // ignore
        }
        return null;
    }

}
